<template>
  <div style="display: flex; flex-direction: column; gap: 10px">
    <p>可自定义标签的级联选择器</p>
    <span>{{ `选值: ${selectedOptions.toString()}` }}</span>
    <el-cascader
      clearable
      filterable
      v-model="selectedOptions"
      :options="optionList"
      placeholder="请选择"
      @expand-change="handleExpandChange"
    >
      <template #default="{ data }">
        <span v-if="data.value">{{ data.label }}</span>
        <div v-else class="add-content" @click.stop>
          <div v-if="editing && data.parent === currentParent" class="add-edit">
            <el-input ref="inputRef" v-model="editLabel" size="small" />
            <el-button link type="primary" @click="addOption">确定</el-button>
            <el-button link @click="onCancelEdit"> 取消</el-button>
          </div>
          <div v-else class="add-icon" @click.stop="handleAddOption(data)">
            <el-icon>
              <Plus />
            </el-icon>
            <span>自定义标签</span>
          </div>
        </div>
      </template>
    </el-cascader>
  </div>
</template>

<script setup lang="ts">
import { Plus } from '@element-plus/icons-vue'
import { nextTick, onMounted, ref } from 'vue'

interface Option {
  label: string
  value: string
  parent: string
  children?: Option[]
}

const inputRef = ref()
const editLabel = ref('')
const currentParent = ref('')
const editing = ref(false)
const optionList = ref<Option[]>([])
const selectedOptions = ref<string[]>([])

onMounted(() => {
  optionList.value.push({ label: '', value: '', parent: '' })
  setLastChildStyle()
})

const handleAddOption = (data: Option) => {
  editLabel.value = ''
  editing.value = true
  currentParent.value = data.parent
  nextTick(() => inputRef.value?.focus())
}

const addOption = () => {
  if (!editLabel.value) {
    return
  }

  const time = new Date().getTime().toString()
  const current = currentParent.value
    ? optionList.value.find((item) => item.value === currentParent.value)?.children
    : optionList.value

  const isHaveChildren = !currentParent.value
  const newItem: Option = {
    label: editLabel.value,
    value: time,
    parent: currentParent.value
  }

  if (isHaveChildren) {
    newItem.children = [{ label: '', value: '', parent: time }]
  }

  current?.splice(-1, 0, newItem)
  editing.value = false
  setLastChildStyle()
}

const onCancelEdit = () => {
  editing.value = false
}

const setLastChildStyle = () => {
  nextTick(() => {
    const ulElements = document.querySelectorAll('ul.el-cascader-menu__list')
    ulElements.forEach((ulElement) => {
      const lastLi = ulElement?.lastElementChild
      const labelDiv = lastLi?.querySelector('.el-cascader-node__label') as HTMLElement
      if (labelDiv) {
        labelDiv.style.padding = '0px'
        labelDiv.style.position = 'relative'
        labelDiv.style.marginLeft = '-20px'
        labelDiv.style.marginRight = '-20px'
      }
    })
  })
}

const handleExpandChange = (value: string[]) => {
  editing.value = false
  currentParent.value = value[0]
  setLastChildStyle()
}
</script>

<style scoped lang="less">
.add-content {
  padding: 0 8px;
}

.add-edit {
  display: flex;
  gap: 5px;
  justify-content: center;
}

.add-icon {
  margin-left: 20px;
  color: #333333;
  display: flex;
  align-items: center;
  gap: 5px;

  &:hover {
    color: #4093ff;
  }
}

//确定取消按钮居左处理
.el-button + .el-button {
  margin-left: 0;
}

// 级联文字最长宽度
.el-cascader-node__label {
  max-width: 150px;
}
</style>
